package com.ssyx.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ssyx.constant.GlobalConstant;
import com.ssyx.constant.RedisConstant;
import com.ssyx.mapper.SeckillTimeMapper;
import com.ssyx.model.activity.SeckillTime;
import com.ssyx.service.SeckillSkuService;
import com.ssyx.service.SeckillTimeService;
import com.ssyx.utils.DateUtil;
import com.ssyx.vo.activity.SeckillSkuVo;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @program: ssyx-parent
 * @className: SeckillTimeServiceImpl
 * @description: 类
 * @data: 2024/3/15 21:24
 * @author: ihu
 * @version: 1.0
 **/

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class SeckillTimeServiceImpl extends ServiceImpl<SeckillTimeMapper, SeckillTime> implements SeckillTimeService {
	@Resource
	private SeckillSkuService seckillSkuService;
	@Resource
	private RedisTemplate redisTemplate;
	
	@Override
	public void saveSeckillTimeListToCache() {
		List<SeckillTime> seckillTimeList = list(Wrappers.<SeckillTime>lambdaQuery().eq(SeckillTime::getStatus,
				GlobalConstant.INTEGER_ONE));
		//以场次名称为key，场次信息为value保存数据到缓存
		Map<String, SeckillTime> nameToSeckillTimeMap =
				seckillTimeList.stream().collect(Collectors.toMap(SeckillTime::getName, e -> e));
		redisTemplate.boundHashOps(RedisConstant.SECKILL_TIME_MAP).putAll(nameToSeckillTimeMap);
		//设置过期时间
		redisTemplate.expire(RedisConstant.SECKILL_TIME_MAP, DateUtil.getCurrentExpireTimes(), TimeUnit.SECONDS);
	}
	
	@Override
	public List<SeckillTime> findAllSeckillTimeListFromCache() {
		List<SeckillTime> seckillTimeList = redisTemplate.boundHashOps(RedisConstant.SECKILL_TIME_MAP).values();
		if (seckillTimeList == null) {
			return new ArrayList<>();
		}
		//设置当前时间的秒杀场次，开场时间降序排列，秒杀结束时间统一为一个时间点（23:00:00）
		List<SeckillTime> seckillTimeDescSortList =
				seckillTimeList.stream().sorted(Comparator.comparing(SeckillTime::getStartTime).reversed()).collect(Collectors.toList());
		Date currentDate = DateUtil.parseTime(new DateTime().toString("HH:mm:ss"));
		boolean isFirst = true;
		for (SeckillTime seckillTime : seckillTimeDescSortList) {
			//场次状态 1：已开抢 2：抢购中 3：即将开抢
			if (DateUtil.dateCompare(seckillTime.getStartTime(), currentDate)) {
				//降序，第一个满足条件的为抢购中
				if (isFirst) {
					//抢购中
					seckillTime.setTimeStaus(GlobalConstant.INTEGER_TWO);
					isFirst = false;
				} else {
					//已开抢
					seckillTime.setTimeStaus(GlobalConstant.INTEGER_ONE);
				}
			} else {
				//即将开抢
				seckillTime.setTimeStaus(GlobalConstant.INTEGER_THREE);
			}
		}
		//页面显示为升序，以开场时间排序升序排列
		return seckillTimeList.stream().sorted(Comparator.comparing(SeckillTime::getStartTime)).collect(Collectors.toList());
	}
	
	@Override
	public Map<String, Object> findHomeData() {
		List<SeckillTime> seckillTimeList = findAllSeckillTimeListFromCache();
		//如果没有到秒杀开始时间段，则获取第一个”即将开抢“时间段场次数据
		//如果已经开始秒杀，则获取秒杀中的时间段场次数据
		//获取秒杀中的数据
		List<SeckillTime> runingSeckillTimeList =
				seckillTimeList.stream().filter(seckillTime -> seckillTime.getTimeStaus().equals(GlobalConstant.INTEGER_TWO)).collect(Collectors.toList());
		//当前秒杀场次
		SeckillTime currentReckillTime = null;
		if (!CollectionUtils.isEmpty(runingSeckillTimeList)) {
			//存在秒杀中场次
			currentReckillTime = runingSeckillTimeList.get(GlobalConstant.INTEGER_ZERO);
		} else {
			//不存在秒杀中场次，则取第一个”即将开抢“时间段场次数据
			currentReckillTime = seckillTimeList.get(GlobalConstant.INTEGER_ZERO);
		}
		//获取场次对应的商品信息
		List<SeckillSkuVo> seckillSkuVoList = seckillSkuService.findSeckillSkuListFromCache(currentReckillTime.getName());
		if (!seckillSkuVoList.isEmpty()) {
			seckillSkuVoList.add(seckillSkuVoList.get(GlobalConstant.INTEGER_ZERO));
		}
		//返回当前场次与对应的商品信息
		Map<String, Object> result = new HashMap<>();
		result.put("seckillTime", currentReckillTime);
		result.put("seckillSkuVoList", seckillSkuVoList);
		return result;
	}
}
